package net.child.chess.gui;

import android.app.Dialog;
import android.content.Context;
import android.widget.GridView;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import net.child.chess.core.Board;
import net.child.chess.utils.ChessDef;
import net.child.chess.utils.Move;
import net.child.chess.pieces.Bishop;
import net.child.chess.pieces.Knight;
import net.child.chess.pieces.Piece;
import net.child.chess.pieces.Queen;
import net.child.chess.pieces.Rook;
import android.widget.Toast;
import android.view.Gravity;
import android.view.View;

public class BoardView extends GridView implements View.OnClickListener
{
	public BoardView(Context context, Board board, int displayWidth)
	{
		super(context);
		LayoutParams layoutParams = 
       	 	new GridView.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
		setLayoutParams(layoutParams);
		mColumWidth = displayWidth / ChessDef.BOARD_NUM_COLUMNS;
        setColumnWidth(mColumWidth);
        setNumColumns(ChessDef.BOARD_NUM_COLUMNS);
        mBoard = board;
		mButtons = new SquareButton[ChessDef.NUM_PIECES];
		for(int i=0; i<ChessDef.NUM_PIECES; ++i)
		{
			Piece piece = mBoard.piece(i);
			mButtons[i] = new SquareButton(getContext(), this, piece, i, mColumWidth, SquareButton.ButtonUsage.GAME_BUTTON);
		}
		setAdapter(new SquareButtonAdapter(mButtons));

		mLastFocusedMoves = new ArrayList<Integer>();
		mLastClickedPiecePosition = -1;	
		mIgnoreClicks = false;
		mGameOverMessage = null;
		mCurrNumPlayerMoves = 0;
		mWaitingPromotionDecision = false;
	}
	
	public void Reset()
	{
		mIgnoreClicks = true;
		
		for(int i=0; i<ChessDef.NUM_PIECES; ++i)
		{
			Piece piece = mBoard.piece(i);
			mButtons[i].piece(piece);
		}
		mLastFocusedMoves.clear();
		mLastClickedPiecePosition = -1;	
		mGameOverMessage = null;
		mCurrNumPlayerMoves = 0;
		mWaitingPromotionDecision = false;
		//	add here any new reset, every member reset should before allowing clicks. 
		
		mIgnoreClicks = false;
	}
	
	public Board board()
	{
		return mBoard;
	}
		
	//	This method is called once the square button is clicked.
	@Override
	public void onClick(View view)
	{
		SquareButton button = (SquareButton)view;
		if(button.usage() == SquareButton.ButtonUsage.PROMOTION_BUTTON)
		{
			mWaitingPromotionDecision = false;
			mPromotionDialog.dismiss();
			Piece promotedPiece = button.piece(); 
			mBoard.promotePiece(promotedPiece);
			mButtons[promotedPiece.position().position()].piece(promotedPiece);
			postUserMoveHandler(promotedPiece.color());
			return;
		}
		if(mIgnoreClicks || mWaitingPromotionDecision)
		{
			return;
		}
		if(mGameOverMessage != null)
		{
			Toast toast = Toast.makeText(getContext(), mGameOverMessage, Toast.LENGTH_SHORT);
			toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
			toast.show();
			return;
		}
		
		Piece piece = button.piece();
		final int buttonPosition = button.position();
		if(buttonPosition == mLastClickedPiecePosition)
		{
			//	already handled.
			return;
		}
		
		//	check if different square was clicked before.
		if(mLastClickedPiecePosition >= 0)
		{	
			//	if the new square is a legal move then we need
			//	to move the piece to that square.
			if(mLastFocusedMoves.contains(buttonPosition))
			{
				ChessDef.Color myColor = mBoard.piece(mLastClickedPiecePosition).color();
				moveIsClicked(mLastClickedPiecePosition, buttonPosition);
				postUserMoveHandler(myColor);
				return;
			}
		}
		
		cancelLastClick();
		if(piece != null)
		{
			if(mBoard.boardParams().computerColor() != piece.color())
			{
				piece.moves(mLastFocusedMoves, mBoard);
				if(mLastFocusedMoves.isEmpty() == false)
				{
					mLastClickedPiecePosition = buttonPosition;
					setBackgroundColorAttribute(SquareButton.BackgroundColorAttribute.VALID_MOVEMONT_COLOR);
				}
			}
		}
	}
	
	private void postUserMoveHandler(ChessDef.Color color)
	{
		if(mWaitingPromotionDecision)
			return;
		
		Board.OpponentState opponentState = mBoard.opponentState(color);
		if(opponentState == Board.OpponentState.KING_IS_MATE)
		{
			mGameOverMessage = KING_IS_MATE_MESSAGE;
		}
		else if(opponentState == Board.OpponentState.KING_IS_STALE)
		{
			mGameOverMessage = KING_IS_STALE_MESSAGE;
		}
		else if(mCurrNumPlayerMoves == mBoard.boardParams().maxMoves())
		{
			mGameOverMessage = KING_IS_NOT_MATE_MESSAGE;
		}
		if(mGameOverMessage != null)
		{
			Toast toast = Toast.makeText(getContext(), mGameOverMessage, Toast.LENGTH_LONG);
			toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
			toast.show();
		}
		else
		{
			moveComputer();
		}
	}
	
	private void moveIsClicked(int from, int to)
	{
		cancelLastClick();
		
		++mCurrNumPlayerMoves;
		
		//	Notify the board that a new move has started.
		mBoard.startNewPlayerMove();
		
		//	save the piece before moving it.
		Piece fromPiece = mBoard.piece(from);
		move(from, to);
		if(fromPiece.shouldBePromoted())
		{
			showPromotionDialog(fromPiece);
		}
		else
		{
			Move extraMove = fromPiece.getExtraMove(mBoard);
			if(extraMove != null)
			{
				move(extraMove.from(), extraMove.to());
			}
		}
	}
	
	private void showPromotionDialog(Piece piece)
	{	
		//	create a grid view for the promotion.
		mPromotionView = new GridView(getContext());
		LayoutParams layoutParams = 
       	 	new GridView.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
		mPromotionView.setLayoutParams(layoutParams);
		final int NUM_COLUMNS = 4;
		mPromotionView.setColumnWidth(mColumWidth);
		mPromotionView.setNumColumns(NUM_COLUMNS);
		SquareButton[] buttons = new SquareButton[NUM_COLUMNS];
		int position = piece.position().position();
		ChessDef.Color color = piece.color();
		buttons[0] = new SquareButton(getContext(), this, new Queen(color, position), 0, mColumWidth, SquareButton.ButtonUsage.PROMOTION_BUTTON);
		buttons[1] = new SquareButton(getContext(), this, new Rook(color, position), 1, mColumWidth, SquareButton.ButtonUsage.PROMOTION_BUTTON);
		buttons[2] = new SquareButton(getContext(), this, new Bishop(color, position), 2, mColumWidth, SquareButton.ButtonUsage.PROMOTION_BUTTON);
		buttons[3] = new SquareButton(getContext(), this, new Knight(color, position), 3, mColumWidth, SquareButton.ButtonUsage.PROMOTION_BUTTON);	
		mPromotionView.setAdapter(new SquareButtonAdapter(buttons));
		
		mPromotionDialog = new Dialog(getContext());
		mPromotionDialog.setContentView(mPromotionView, layoutParams);
		mPromotionDialog.setTitle("Select Promotion Piece:");
		mPromotionDialog.setCancelable(false);
		mPromotionDialog.show();
		
		mWaitingPromotionDecision = true;
	}
	
	private void move(int from, int to)
	{
		Piece fromPiece = mBoard.piece(from);
		
		//	remove the piece from previous position.
		mButtons[from].piece(null);
		
		if(to != ChessDef.KILL_MOVE)
		{
			//	Move the piece to the new position.
			mButtons[to].piece(fromPiece);
		}
		
		//	now update the board with this move.
		mBoard.move(from, to);
	}
	
	//	Iterate over all buttons in mLastFocusedMoves and change thier attribute
	private void setBackgroundColorAttribute(SquareButton.BackgroundColorAttribute attribute)
	{
		Iterator<Integer> iter = mLastFocusedMoves.iterator();
		while(iter.hasNext())
		{
			int position = iter.next();
			SquareButton currButton = mButtons[position];
			currButton.setBackgroundColorAttribute(attribute);
		}
	}
	
	private void cancelLastClick()
	{
		setBackgroundColorAttribute(SquareButton.BackgroundColorAttribute.ORIGINAL_COLOR);
		mLastClickedPiecePosition = -1;
		mLastFocusedMoves.clear();
	}
	
	//	Implement simple algorithm for the computer movement. 
	private void moveComputer()
	{
		Move move = mBoard.randomMove(mBoard.boardParams().computerColor());
		//	save the piece before moving it.
		Piece fromPiece = mBoard.piece(move.from());
		move(move.from(), move.to());
		Move extraMove = fromPiece.getExtraMove(mBoard);
		if(extraMove != null)
		{
			move(extraMove.from(), extraMove.to());
		}
	}
	
	private Board mBoard;
	private SquareButton[] mButtons;
	private int mColumWidth;
	
	//	if the player clicked on a piece then we will
	//	save information on the legal moves of this piece
	private List<Integer> mLastFocusedMoves;
	// negative value means that no square was clicked.
	private int mLastClickedPiecePosition; 
	
	//	we should any click while reseting the board.
	boolean mIgnoreClicks;
	
	private static String KING_IS_MATE_MESSAGE     = "The king is mate :)";
	private static String KING_IS_NOT_MATE_MESSAGE = "The king isn't mate :(";
	private static String KING_IS_STALE_MESSAGE     = "The king is stale :(";
	//	if mGameOverMessage isn't null then the gave is over and we should
	//	print this message.
	String mGameOverMessage;
	
	private int mCurrNumPlayerMoves;
	
	private boolean mWaitingPromotionDecision;
	private Dialog mPromotionDialog;
	GridView mPromotionView;
}

